using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace Verlet
{
    class Limb : Constraint
    {
        public Node root, joint, end;
        Link upper, lower, grip;
        Vector3 target;
        float ballisticTimeRemaining = 0f;
        bool inBallisticMotion = false;
        
        public Limb(float radius, float upperLength, float lowerLength)
        {
            root = new Node();
            joint = new Node();
            end = new Node();
            upper = new Link(root, joint, upperLength, radius);
            lower = new Link(joint, end, lowerLength, radius);
        }

        public void Grab(Node n)
        {
            grip = new Link(end, n, 0f, 0f);
        }

        public void Ungrab()
        {
            grip = null;
        }

        public override void Constrain()
        {
            upper.Constrain();
            lower.Constrain();
            if (grip != null)
                grip.Constrain();
        }

        public void Draw(Device d)
        {
            upper.Draw(d);
            lower.Draw(d);
        }

        public void Update()
        {
            root.Update();
            joint.Update();
            if (InBallisticMotion)
            {
                float motionTime = Node.deltaT;
                if (motionTime > ballisticTimeRemaining)
                {
                    motionTime = ballisticTimeRemaining;
                    inBallisticMotion = false;
                    end.ControlMode = ControlMode.FallAndStick;
                }
                float fractionOfDistance = motionTime / ballisticTimeRemaining;
                Vector3 remainingDistance = target - end.Position;
                end.Position += fractionOfDistance * remainingDistance;
                ballisticTimeRemaining -= motionTime;
            }
            end.Update();
        }

        public bool InBallisticMotion
        {
            get
            {
                return inBallisticMotion;
            }
        }

        public void CancelBallisticMotion() {
            ballisticTimeRemaining = 0f;
        }

        public void Goto(Vector3 target, float time)
        {
            end.ControlMode = ControlMode.Free;
            this.target = target;
            ballisticTimeRemaining = time;
            inBallisticMotion = true;
        }

        public float Extension
        {
            get
            {
                Vector3 offset = root.Position - end.Position;
                return offset.Length() / (upper.length + lower.length);
            }
        }
    }
}
